﻿using Internal;
using System.Net.Http;
using System.Linq;
using Daemon.Common;
using Daemon.Common.Helpers;
using Daemon.Infrustructure.EF;
using Daemon.Repository.EF.Enums;
using Daemon.Repository.Contract;
using Daemon.Model;
using Daemon.Model.Entities;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;

namespace Daemon.Repository.EF
{
    public class AdminUserRepository : Repository<AdminUser>, IAdminUserRepository
    {
        protected override Expression<Func<AdminUser, int>> PrimaryKeyExpression => r => r.Id;
        private readonly IUserRoleRepository _userRoleRepository;

        public AdminUserRepository(ApiDBContent context, IUserRoleRepository userRoleRepository) : base(context)
        {
            _userRoleRepository = userRoleRepository;
        }

        protected override IEnumerable<AdminUser> IncludeRelationships(IEnumerable<AdminUser> entities, ApiDBContent context)
        {
            DecryptPassword(entities);
            SetUserRole(entities, context);
            SetLoginInfo(entities, context);
            SetDeptInfo(entities, context);
            return entities;
        }

        protected override void UpdateEntitiesBeforeCreate(IEnumerable<AdminUser> entities, ApiDBContent context)
        {
            EncryptPassword(entities);
        }

        protected override void UpdateEntitiesBeforeUpdate(IEnumerable<AdminUser> entities, ApiDBContent context)
        {
            EncryptPassword(entities);
        }

        private void SetLoginInfo(IEnumerable<AdminUser> entities, ApiDBContent db)
        {
            if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, AdminUserRelationshipEnum.LoginInfo))
            {
                return;
            }

            var userIds = entities.Select(r => r.Id).ToList();
            var sessionInfos = db.UserSession.Where(r => userIds.Contains(r.UserId)).OrderByDescending(r => r.Id).AsEnumerable().GroupBy(r => r.UserId).ToDictionary(r => r.Key, r => r.ToList());
            foreach (var entity in entities)
            {
                if (sessionInfos.TryGetValue(entity.Id, out List<UserSession> sessionInfo))
                {
                    entity.LastLoginTime = sessionInfo.OrderByDescending(r => r.LoginTime).FirstOrDefault()?.LoginTime;
                }
            }
        }

        private void SetDeptInfo(IEnumerable<AdminUser> entities, ApiDBContent db)
        {
            if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, AdminUserRelationshipEnum.DeptInfo))
            {
                return;
            }

            var userIds = entities.Select(r => r.Id).ToList();
            var userDeptDic = db.UserDepartments.Where(r => userIds.Contains(r.UserId)).ToDictionary(r => r.UserId, r => r.DeptId);
            foreach (var entity in entities)
            {
                if (userDeptDic.TryGetValue(entity.Id, out int deptId))
                {
                    entity.DeptId = deptId;
                }
            }
        }

        private void SetUserRole(IEnumerable<AdminUser> entities, ApiDBContent db)
        {
            if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, AdminUserRelationshipEnum.UserRole))
            {
                return;
            }

            var userIds = entities.Select(r => r.Id).ToList();
            _userRoleRepository.SetRelationships(new List<Relationship>() { new Relationship() { Name = UserRoleRelationship.RoleInfo.ToString() } });
            var allUserRoles = _userRoleRepository.IncludeRelationships(db.UserRole.Where(r => userIds.Contains(r.UserId))).ToList();
            foreach (var entity in entities)
            {
                var userRoles = allUserRoles.Where(r => r.UserId == entity.Id).ToList();
                if (userRoles.Any())
                {
                    entity.UserRoles = userRoles;
                }
            }
        }

        private void EncryptPassword(IEnumerable<AdminUser> entities)
        {
            foreach (var entity in entities)
            {
                entity.Password = PasswordHelper.Rfc2898Encrypt(entity.Password, "daemon");
            }
        }

        private void DecryptPassword(IEnumerable<AdminUser> entities)
        {
            if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, AdminUserRelationshipEnum.Password))
            {
                return;
            }

            foreach (var entity in entities)
            {
                entity.Password = PasswordHelper.Rfc2898Decrypt(entity.Password, "daemon");
            }
        }
    }
}